package rest.jbpm.svg;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import rest.jbpm.wrappers.Duration;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;

public class SVGBuilder {

    private Document jpdl = null;
    private String outSVG = "";
    private Set<String> activeElements = null;
    private Map<String,Number> elementDurations = null;
    private Map<String,Map<String,Number>> choiseDistributions = null;

    public String getSVGAsString(){
        return outSVG;
    }

    public void addJPDL(InputStream is) throws DocumentException {
        SAXReader reader = new SAXReader();
        jpdl = reader.read(is);
    }

    public void addJPDL(File f) throws DocumentException {
        SAXReader reader = new SAXReader();
        jpdl = reader.read(f);
    }

    public void addJPDL(URL url) throws DocumentException {
        SAXReader reader = new SAXReader();
        jpdl = reader.read(url);
    }

    public void setActiveElements(Set<String> aE){
        activeElements = aE;
    }

    public void setElementDurations(Map<String,Number> elDurat){
        elementDurations = elDurat;
    }

    public void setChoiseDistributions(Map<String,Map<String,Number>> chDist){
        choiseDistributions = chDist;
    }

    public void build() throws IOException {


        if (jpdl == null)
            throw new IllegalStateException("No JPDL definition has been set. Nothing to draw in SVG.");

        //JBPM всего-то двухуровневый

        Element root_el = jpdl.getRootElement();
        //System.out.print(root_el.getName() + "\n");

        // хранилище имя => состояние JPDL
        Map<String,JbpmElement> model = new HashMap<String,JbpmElement>();

        // хранилище связующих линий
        Set<JbpmTransition> transitions = new HashSet<JbpmTransition>();

        for ( Iterator i = root_el.elementIterator(); i.hasNext(); ) {
            Element el = (Element) i.next();

            //System.out.print("\t"+el.getName()+"\n");

            JbpmElement jbmpEl = JbpmElementFactory.createElement(el);
            model.put(el.attribute("name").getValue(),jbmpEl);

            for (Iterator j = el.elementIterator(); j.hasNext(); ){
                Element tr = (Element) j.next();
                if (tr.getName().equalsIgnoreCase("transition")){

                    // формируем элемент перехода
                    JbpmTransition trans = new JbpmTransition(el.attribute("name").getValue(), tr);

                    // кормим статистику по переходам
                    if (choiseDistributions != null)
                        trans.setChoiseDistribution(choiseDistributions.get(el.attribute("name").getValue()));

                    transitions.add(trans);
                }

            }
        }

        //System.out.print("States: " + model.keySet().size()+"\n");
        //System.out.print("Transitions: " + transitions.size()+"\n");



        // простановка активных элементов, если есть
        if (activeElements != null)
        for (String activeName:activeElements){
            model.get(activeName).setActive();
        }

        // Добавляем длительность процессов, если есть
        if (elementDurations != null){
            for (String d:elementDurations.keySet()){
                if (model.containsKey(d))
                    model.get(d).setDuration(elementDurations.get(d));
            }
        }

        // Добавляем распределение переходов


        // Вывод в файл

        ByteArrayOutputStream os = new ByteArrayOutputStream();

        // Рисование SVG: кэширование
        String osCache = "";

        // Переходы
        for (JbpmTransition iTr:transitions){
            osCache+=iTr.draw(model);
        }

        // Состояния
        for (JbpmElement iEl:model.values()){
            osCache+=iEl.draw();
        }

        // Подписи переходов
        for (JbpmTransition iTr:transitions){
            osCache+=iTr.drawLabel();
        }

        // Выясняем ~ размеры картинки для её масштабирования
        int maxX=0,maxY=0;
        for(JbpmElement iEl:model.values()){
            if (iEl.getXMax() > maxX)
                maxX = iEl.getXMax();
            if (iEl.getYMax() > maxY)
                maxY = iEl.getYMax();
        }
        for (JbpmTransition iTr:transitions){
            int _maxX = iTr.getXMax();
            if (_maxX > maxX)
                maxX = _maxX;
            int _maxY = iTr.getYMax();
            if (_maxY > maxY)
                maxY = _maxY;
        }

        // Рисование SVG
        os.write(("<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"\nxmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 "+maxX+" "+maxY+"\" preserveAspectRatio=\"xMidYMid\">").getBytes("UTF-8"));
        os.write(osCache.getBytes("UTF-8"));

        // Список текущих тасков
        /*
        if (tasks != null){
            String tasklist = "<foreignObject x=\"300\" y=\"10\" width=\"800\" height=\"800\">\n<body xmlns=\"http://www.w3.org/1999/xhtml\">\n<table>";
            for (Task t:tasks){
                tasklist+="<tr><td>"+t.getActivityName()+"</td><td>"+t.getName()+"</td><td>"+t.getDescription()+"</td><td>"+t.getAssignee()+"</td><td>"+t.getCreationTime()+"</td><td>"+t.getDuedate()+"</td></tr>";
            }
            tasklist+="</table>\n</body>\n</foreignObject>";
            os.write(tasklist.getBytes("UTF-8"));
        } */

        // Конец документа
        os.write("</svg>".getBytes("UTF-8"));
        os.close();

        outSVG = os.toString("UTF-8");
    }

    public static void main(String argc[]) throws IOException, DocumentException {

        String arg = "leave.vacation.orders.bmstu.org.jpdl.xml";

        //for (String arg: argc){
            File inJbpmFile = new File(arg);
            File outSVG = new File(arg+".svg");
            if (outSVG.exists())
                outSVG.delete();
            outSVG.createNewFile();

            /*if (jpdlToSVG(inJbpmFile,outSVG))
                System.out.print("'"+arg+"' => '"+arg+".svg' : okay\n");
            else
                System.out.print("'"+arg+"' => '"+arg+".svg' : fail!\n");
                */
        //
        // }

        //BufferedInputStream inJbpm = new BufferedInputStream(new FileInputStream(inJbpmFile));

        return;
    }
}

